#include "http-session.h"

#include "util/logger/logger.h"

#include "http-request.h"
#include "http-response.h"
#include "http-server.h"
#include "http-dispatcher.h"
#include "http-controller.h"


static const char *name() {
    return "HttpSession ";
}

HttpSession::HttpSession(HttpServer &server)
    : server_(server) {
}

HttpSession::~HttpSession() {
}

void HttpSession::removeSelf()
{
    server_.remove(this);
}

void HttpSession::startHandleMessage()
{
    asyncReadRequest();
}

void HttpSession::afterOneRequestCompleted(std::error_code err) {
    clearPerRequestData();
    stop();
}

void HttpSession::clearPerRequestData() {
    request_ = UnderRequest();
    requestBuffer_.clear();
    response_ = UnderResponse();
}

void HttpSession::stop() {
    LOGD << name() << "stop";
    removeSelf();
}

void HttpSession::asyncReadRequest() {
    asyncReadHttpRequest(requestBuffer_, request_, [this](std::error_code err, size_t readn) {
        if (err.value() == int(beast::http::error::end_of_stream)) {
            LOGD << name() << "async_read callback with end_of_stream";
            stop();
            return;
        }

        if (err) {
            LOGE << name() << "async_read callback with error: " << err.message();
            stop();
            return;
        }
        
        HttpRequest req(std::move(request_));

        // 不直接使用底层模块提供的响应类，而是定义一个中间的类。
        // 这是因为底层模块提供的响应类的响应内容的类型是通过模板在编译器确定的，
        // 但是这不是需要的效果，更好的效果是在运行时可以根据资源类型决定如何提供相应内容。
        // 例如对于动态资源，需要每次分配内存以便写入动态内容，而对于静态资源，则只需要提供一个视图。
        HttpResponse resp;

        // 处理请求
        handleHttpRequest(req, resp);

        if (resp.isDiscarded()) {
            stop();
            return;
        }

        // 设置HTTP状态码
        response_.result(static_cast<unsigned>(resp.statusCode()));

        // 取走缓冲对象，保存在连接对象中
        responseBufferHolder_ = resp.takeBuffer();
        
        // 设置响应内容
        response_.body() = responseBufferHolder_;
        response_.prepare_payload();

        // 设置响应类型
        response_.set(beast::http::field::content_type, resp.contentType().str());

        // 设置etag
        if (const std::string *etag = resp.etag()) {
            response_.set(beast::http::field::etag, *etag);
        }

        // 设置gzip压缩标记
        if (resp.isGzipped()) {
            response_.set(beast::http::field::content_encoding, "gzip");
        }
        
        // 发送响应
        asyncWriteHttpResponse(response_, [this] (std::error_code err, size_t n) {
            afterOneRequestCompleted(err);
        });
    });
}

void HttpSession::handleHttpRequest(const HttpRequest &request, HttpResponse &response) {
    LOGD << name() << "handle request: " << request.logInfo();

    HttpController *controller = server_.dispatcher().dispatch(request);
    if (controller) {
        controller->handleHttpRequest(request, response);
    } else {
        response.setStatusCode(HttpStatusCode::NotFound);
        LOGE << name() << "controller not found by request: " << request.logInfo();
    }
}



